#ifndef _MCP_H_
#define _MCP_H_

// "Global" headers that may be assumed to be included.

#include <stdio.h>
#include <errno.h>
#include <assert.h>
#include <string>
 using std::string;
#include <list>
 using std::list;
#include <vector>
 using std::vector;

#include "utility.h"
#include "preferences.h"

#ifndef PATH_MAX
    // conservative fallback -- only needed for the config file. 
    #define PATH_MAX 256
#endif

class Client;
class UI;
class ConfigFile;
class MediaInfo;

class UIList;

enum Command
    {
    COMMAND_CONNECT,
    COMMAND_DISCONNECT,
    COMMAND_PREVIOUS,
    COMMAND_NEXT,
    COMMAND_PAUSE,
    COMMAND_PLAY,
    COMMAND_STOP,
    COMMAND_LAST,
    COMMAND_FIRST,
    COMMAND_MUTE,
    COMMAND_UNMUTE
    };

enum Event
    {
    EVENT_LAUNCHING,
    EVENT_CONNECTED,
    EVENT_DISCONNECTED,
    EVENT_PLAYING,
    EVENT_PAUSED,
    EVENT_STOPPED,
    EVENT_POSITION,
    EVENT_ID,
    EVENT_CURRENT_INFO,
    EVENT_PICTURE_DATA,
    EVENT_PLAYTIME,
    EVENT_PLAYLIST,
    EVENT_PLAYLIST_INFO,
    EVENT_VOLUME
    };

struct event_picture_data
    {
    unsigned int   id;
    unsigned char *data;
    unsigned int   length;
    string        *xmms_hash;
    };

typedef union
    {
    unsigned int id;
    struct event_picture_data picture;
    }
EventData;

class MCP
    {
  public:
    ConfigFile  *cfg;
    Preferences *prefs;
    Client      *xmms;

    int verbose;  // 0:none  1:minimal  2:default
                  // 5:verbose  10:debug  11:spammer  12:spammer w/Tourette's
    bool log_verbose(int min_level, const char *format, ...);
    void logf(bool confirm, const char *format, ...);

    // Current song data, may be zero/null if not [yet] available
    int            playlist_position;
    unsigned int   song_position,
                   song_length;
    unsigned int   total_song_length;
    MediaInfo     *current_info;
    // Overall data
    unsigned int   total_song_length_previous;
    unsigned int   playlist_length;
    unsigned int   volume_left,
                   volume_right;
    unsigned char *picture_data;    /// these are only valid
    unsigned int   picture_length;  //  during EVENT_PICTURE_DATA

    // UI Requests
    unsigned int current_id();
    bool connect();
    bool connected();
    bool playing();
    bool paused();
    bool stopped();
    bool muted();
    bool command(Command cmd);
    void maintain_playtime(bool enable);
    void change_position(unsigned int position_ms);
    void change_volume(int change, bool absolute=true);
    void request_picture(unsigned int id);

    void write_config();

  friend class Client;
    // client Change of State Notifications
    void connected_event();
    void disconnected_event();
    void playing_event();
    void paused_event();
    void stopped_event();
    void playtime_event(unsigned int new_playtime);
    void volume_event(unsigned int left, unsigned int right);
    void position_event(int new_pos);
    void id_event(unsigned int new_id);
    void playlist_event();

    // client Info Notifications
    void playlist_updated();
    void playlist_info_updated();
    void current_info_updated(MediaInfo *info);
    void picture_loaded(unsigned int id, unsigned char *data,
                        unsigned int length, string *hash);

  protected:
    UIList *ui_list;

    void clear_state();
    void add_UI(UI *obj);
    void remove_UI(UI *obj);
    void init_config();
    void fire_event(Event event);
    void fire_event(Event event, EventData *event_data);

  friend int main(int argc, char *argv[]);
    MCP();
    ~MCP();
    bool prestartup();
    void mainloop();
    };

extern MCP *mcp;  // The MCP is mighty and gets a global object.

#endif // _MCP_H_
